var sql = require('./sqlite3').verbose(),
	app = require('http').createServer(handler),
	io = require('./socket.io').listen(app),
	db = new sql.Database('../db/app.db'),
	ex = require('./node.extend'),
	cy = require('crypto'),
	fs = require('fs');

// start the server
app.listen(8080);

// HELPER FUNCTIONS
// ----------------------

// the http server handler
var handler = function(req, res) {
	fs.readFile(__dirname + '/index.html', function (err, data) {
		if(err) {
			res.writeHead(500);
			return res.end('Error loading index.html');
		}

		res.writeHead(200);
		res.end(data);
	});
};

// decode an auth token
var decode = function(t) {
	var decoded = new Buffer(t, 'base64').toString('ascii'),
		length = parseInt(decoded.substr(0, 1)),
		id = decoded.substr(1, length),
		password = decoded.substr(length + 1),
		sql = "SELECT id, name, email FROM users WHERE id = ? AND password = ?";

	return {sql: sql, id: id, password: password};
};

// url safe text
var named_id = function(text) {
	var newtext = '',
		lastaddto = '',
		regex = /[a-zA-Z0-9\-\_]/;

	text = text.replace(' ', '-').toLowerCase();
	for(var i = 0; i < text.length; i++) {
		var addto = '-';
		if(regex.test(text[i])) {
			addto = text[i];
			lastaddto = '';
		}

		if(lastaddto != '-')
			newtext += addto;

		lastaddto = addto;
	}

	if(newtext.substr(-1) == '-')
		newtext = newtext.substr(0, newtext.length - 1);

	return newtext;
};

// attach arbitrary data
var attach = function(data, obj) {
	data.avatar = cy.createHash('md5').update(data.email.toLowerCase()).digest("hex");
	data.link = data.id + '-' + named_id(data.name);

	delete obj.token;
	delete data.email;
	return ex(data, obj);
};

// ----------------------

// define the users list
var list = {};

// settings
io.enable('browser client minification');
io.enable('browser client etag');
// io.enable('browser client gzip');

// more settings
// io.set('log level', 1);
io.set('origins', 'prototype.local:8080,air.zapto.org:8080');

// on connect
io.sockets.on('connection', function (socket) {
	// simple callback secured with token
	var _simple = function(token, f) {
		// no token? no access
		if(!token)
			return;

		// decode our token
		var decoded = decode(token);

		// get the user
		db.get(decoded.sql, decoded.id, decoded.password, function(error, row) {
			// nothing found?
			if(typeof row == 'undefined')
				return;

			// callback?
			if(f) f();
		});
	};

	// on announce broadcast it
	socket.on('announce', function(obj) {
		_simple(obj.token, function() {
			socket.broadcast.emit('announce', obj.data);
		});
	});

	// on metro emit & broadcast it
	socket.on('metro', function(obj) {
		_simple(obj.token, function() {
			socket.emit('metro', obj.data);
			socket.broadcast.emit('metro', obj.data);
		});
	});

	// on noty broadcast it
	socket.on('noty', function(obj) {
		_simple(obj.token, function() {
			socket.broadcast.emit('noty', obj.data);
		});
	});

	// on rank emit & broadcast it
	socket.on('rank', function(obj) {
		_simple(obj.token, function() {
			socket.emit('rank', obj.data);
			socket.broadcast.emit('rank', obj.data);
		});
	});

	// set status
	var _status = function(status, token) {
		// decode our token
		var decoded = decode(token);

		// get the user
		db.get(decoded.sql, decoded.id, decoded.password, function(error, row) {
			// nothing found?
			if(typeof row == 'undefined')
				return;

			// get the user
			socket.get('user', function (err, data) {
				// no data? return here
				if(data == null)
					return;

				// if status arg is away
				if(status == 'away') {
					// already set to away? or to busy?
					if(data.status == 'away' || data.status == 'busy')
						return;
				}

				// if status arg is busy
				if(status == 'busy') {
					// already set to away?
					if(data.status == 'busy')
						return;
				}

				// set to away
				data.status = status;

				// set data in socket
				socket.set('user', data);
				list[data.id] = data;

				// emit and broadcast refresh
				socket.emit(status, data.id);
				socket.broadcast.emit(status, data.id);
			});
		});
	};

	// on away, just chnage the status
	socket.on('away', function (token) {
		// no token? no access
		if(!token)
			return;

		// set status
		_status('away', token);
	});

	// on busy, just chnage the status again
	socket.on('busy', function (token) {
		// no token? no access
		if(!token)
			return;

		// set status
		_status('busy', token);
	});

	// on join set and broadcast user and data
	socket.on('join', function (obj) {
		// no token? no access
		if(!obj.token)
			return;

		// guest user? refresh list
		if(obj.token == 'guest')
			return socket.emit('online', list);

		// decode our token
		var decoded = decode(obj.token);

		// get the user
		db.get(decoded.sql, decoded.id, decoded.password, function(error, row) {
			// nothing found?
			if(typeof row == 'undefined')
				return;

			// attach arbitrary
			data = attach(row, obj);

			// set data in socket
			socket.set('user', data);
			list[data.id] = data;

			// emit and broadcast refresh
			socket.emit('online', list);
			socket.broadcast.emit('online', list);
		});
	});

	// offline function
	var _offline = function() {
		// get the user
		socket.get('user', function (err, data) {
			// no data? return here
			if(data == null)
				return;

			// remove the user from list
			delete list[data.id];

			// emit and broadcast offline
			socket.del('user');
			socket.emit('offline', data.id);
			socket.broadcast.emit('offline', data.id);
		});
	};

	// on leave or disconnect use the leave function
	socket.on('leave', _offline);
	socket.on('disconnect', _offline);
});